在上一段我們介紹了許多元件,不過並沒有介紹怎樣讓按鈕按下後執行某些事,或是怎樣改變 TextInput 的 value 值。先讓我們回到 HTML 的世界看看我們過去是怎樣觸發事件的:
<button onclick="console.log('click')">按鈕</button>
當點擊這個按鈕時,會在 console 面板印出 click 的字串。那麼,在 JSX 中,要怎樣改寫上面的程式碼呢?答案是把 onclick 改成小駝峰寫法,用大括號包覆 JS 的處理。並且最重要的一點是,如果需要傳入參數,那就要用箭頭函式來撰寫,才會正確的在點擊時才被觸發。
{/* 正確寫法:只有點擊按鈕時,才會觸發 console.log('click') */}
<button onClick={() => console.log('click')}>按鈕</button>
{/* 錯誤寫法:第一次渲染就觸發 console.log('click) ,之後點擊按鈕都不會有任何 console.log() */}
<button onClick={console.log('click')}>按鈕</button>
如果你並沒有要傳入參數,只是呼叫一個函式,那也可以不用以箭頭函式撰寫:
function App() {
const handleClick = () => {
console.log('click');
};
const handleClick2 = param => {
console.log(param);
};
return (
{/* 正確寫法*/}
<button onClick={handleClick}>按鈕</button>
{/* 也是正確寫法*/}
<button onClick={() => handleClick()}>按鈕</button>
{/* 函式傳入參數的寫法*/}
<button onClick={() => handleClick2('click')}>按鈕</button>
回到 React Native 的按鈕 TouchableOpacity ,我們不能使用 onClick 來處理事件,因為手機是用手去 press 而不是 click 。因此要這樣改寫:
<TouchableOpacity onPress={() => console.log('pressed')}>
<Text>這是一個按鈕</Text>
</TouchableOpacity>
Tips :以防你學到這邊對 JSX 的幾個重要特性還沒辦法駕輕就熟,讓我簡單統整一下。
- 最外層只能有一個根元件。
- 要渲染變數、載入樣式、呼叫事件、執行一段 JS 時,都要用一個大括號來包覆。例如:
style={styles.dangerText}
/onPress={handlePress}
。- 樣式被包在物件當中,有兩個以上時以逗號隔開。屬性要用小駝峰寫法,值除了數字都要用字串來傳遞。例如
{fontSize: 20, color: ‘red’}
。- 事件處理的事件觸發方式要用小駝峰寫法。要傳入參數時,需改寫為箭頭函式,否則無法正確觸發。例如:
onPress={()=>console.log(‘pressed’)}
在前面,我們撰寫了簡單的程式碼來載入一個 TextInput ,就像這樣:
function App() {
const text = 'input value';
return (
<TextInput value={text} />
);
}
要讓 TextInput 的值改變,就必須去更動 value 綁定的 text 變數。我們應該如何正確的在 React 中更新一個變數的值呢?首先,在 React 中,我們將這些資料稱呼為 State 。要更動 State ,只能夠透過 setState() 賦予一個新的值。因此,在繼續談 TextInput 的範例前,我們先岔出來聊聊 State 和 setState() 。
從 React 16.8 後,發展出 Hooks ,也就是 React 提供開發者一些小工具,讓我們能快速達到某些效果。而 useState() 就是其中之一。他最主要的目的,是讓我們初始化一個 State ,讓我們能自由的命名 State 和用來更新該 State 的方法(過往統一被稱為 setState)。舉例來說:
import React, {useState} from 'react';
function App() {
const [text, setText] = useState('input value');
在上方的程式碼中,我們宣告了一個名為 text 的變數,用 useState 使他的初始值為字串 input value 。並且提供一個名叫 setText 的方法,能透過呼叫他來更新 text 的值。
使用 Hooks 有幾個注意事項,包含:
import React, {useEffect, useState} from 'react';
import Card from './components/Card';
import TypeSelector from './components/TypeSelector';
import {View, SafeAreaView, ScrollView, StyleSheet} from 'react-native';
// 錯誤寫法:
const [wrongExample, setWrongExample] = useState('錯誤');
function App() {
// 正確寫法:
const [correctExample, setCorrectExample] = useState('正確');
// 錯誤寫法:
const wrongExampleFunction = () =>{
const [wrongExample, setWrongExample] = useState('錯誤');
}
const wrongExampleFunction = () => {
if (true) {
const [wrongExample, setWrongExample] = useState('錯誤');
}
};
const wrongExampleFunction2 = () => {
for (let i = 0; i < 3; i++) {
const [wrongExample2, setWrongExample2] = useState('錯誤');
}
};
運用上一節所學到的事件處理,設計一個按鈕,按下去的時候呼叫 setText() 。可以觀察到按下去後, text 的值被更新,畫面也更新了:
import React, {useState} from 'react';
import {
SafeAreaView,
View,
TextInput,
Text,
TouchableOpacity,
} from 'react-native';
function App() {
const [text, setText] = useState('input value');
return (
<SafeAreaView>
<View>
<TextInput value={text} />
<TouchableOpacity onPress={() => setText('input value changed')}>
<Text>按下去改變 input 值</Text>
</TouchableOpacity>
接著問題就剩下怎樣在每次 input 內容改變時,更新 text 值,好讓 TextInput 可以即時顯示出正確的內容。這時我們會需要用到 onChangeText 這個事件,他的參數會直接等同於目前新的值,因此只要傳入這個新的值,就能正確同步更新 text 了。
<TextInput value={text} onChangeText={newText => setText(newText)} />
寫習慣 HTML 可能會直覺先想到使用 onChange ,而不是 onChangeText 。事實上, React Native 的 TextInput 的確也能使用 onChange 來監聽沒錯,不過他取得值的方式較為複雜。因此直接使用 onChangeText 會比較直觀,也方便撰寫。
<TextInput
value={text}
onChange={({nativeEvent: {eventCount, target, text}}) =>
console.log(text)
}
/>
到這裡為止,雖然對 State 、 setState 、 useState 還矇矇懂懂,但你已經掌握基礎實作。我會用下面的章節深入介紹 useState 是怎樣讓我們能自己定義變數 text 和 setText ? React 又是怎樣處理資料更新機制?